#!/usr/bin/python

import random
import socket
import struct
import sys


def select_service(service):
    while True:
        try:
            return service_mappings[service]
        except KeyError:
            print("Please specify a valid service!!!")
            break

def usage():
    print("\n\tUsage: banner <host> <service>\n\n"
    "\tBannerable services include: 'ftp', 'http', 'https', 'smtp', 'snmpv1', "
    "'snmpv2', 'ssh', 'telnet'\n\n"
    "\tHost can be specified by IP address or domain name.\n")

def banner_tcp(HOST, PORT, PACKET):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(5)
        s.connect((HOST, PORT))
        s.sendall(PACKET.encode('utf-8'))
        reply = s.recv(1024)
        print("{}".format(reply.decode('utf-8')))
    except socket.error as error:
        print(error)

def ftp(HOST):
    PORT = 21
    PACKET = ""
    banner_tcp(HOST, PORT, PACKET)

def http(HOST):
    PORT = 80
    PACKET = 'HEAD / HTTP/1.1\r\nHost: {}\r\n\r\n'.format(HOST)
    banner_tcp(HOST, PORT, PACKET)

def https(HOST):
    PORT = 443
    PACKET = ''
    banner_tcp(HOST, PORT, PACKET)

def ident(HOST):
    PORT = 113
    PACKET = '1234, 1234'
    banner_tcp(HOST, PORT, PACKET)

def netbios(HOST):
    PORT = 137

    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect((HOST, PORT))
        PACKET = struct.pack('!hhhhhhb32sbhh', 8999, 0, 1, 0, 0, 0, 32, 
                             'CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 0, 33, 1)
        s.sendall(PACKET.encode('utf-8'))
        reply = s.recv(1024)
        reply = unicode(reply, errors='ignore')
        print("{}".format(reply))
    except socket.error as error:
        print("{}".format(error))

def rsync(HOST):
    PORT = 873
    PACKET = ''
    banner_tcp(HOST, PORT, PACKET)

def smtp(HOST):
    PORT = 25
    PACKET = ''
    banner_tcp(HOST, PORT, PACKET)

def snmpv1(HOST):
    PORT = 161
    SNMPver = 0
    COMMSTR = b'public'
    w = random.randint(1, 255)
    x = random.randint(1, 255)
    y = random.randint(1, 255)
    z = random.randint(1, 255)

    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.settimeout(7)
        s.connect((HOST, PORT))
        snmp_get = struct.pack('bbbbbbb6sBbbbBBBBbbbbbbbbbbbbbbbbbbbbbb', 48, 
                               41, 2, 1, SNMPver, 4, 6, COMMSTR, 160, 28, 2, 
                               4, w, x, y, z, 2, 1, 0, 2, 1, 0, 48, 14, 48, 
                               12, 6, 8, 43, 6, 1, 2, 1, 1, 1, 0, 5, 0)
        s.sendall(snmp_get)
        reply = s.recv(1024)
        reply = reply.decode('utf-8', errors='ignore')
        print(reply)
    except socket.error as error:
        print(error)

def snmpv2(HOST):
    PORT = 161
    SNMPver = 1
    COMMSTR = b'public'
    w = random.randint(1, 255)
    x = random.randint(1, 255)
    y = random.randint(1, 255)
    z = random.randint(1, 255)

    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.settimeout(7)
        s.connect((HOST, PORT))
        snmp_get = struct.pack('bbbbbbb6sBbbbBBBBbbbbbbbbbbbbbbbbbbbbbb', 48, 
                               41, 2, 1, SNMPver, 4, 6, COMMSTR, 160, 28, 2, 
                               4, w, x, y, z, 2, 1, 0, 2, 1, 0, 48, 14, 48, 
                               12, 6, 8, 43, 6, 1, 2, 1, 1, 1, 0, 5, 0)
        s.sendall(snmp_get)
        reply = s.recv(1024)
        reply = reply.decode('utf-8', errors='ignore')
        print(reply)
    except socket.error as error:
        print(error)

def ssh(HOST):
    PORT = 22
    PACKET = ''
    banner_tcp(HOST, PORT, PACKET)

def telnet(HOST):
    PORT = 23
    PACKET = '\r\n\r\n'
    banner_tcp(HOST, PORT, PACKET)

def tftp(HOST):
    if sys.argv[2] == "tftp":
        PORT = 69
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.settimeout(7)
            s.connect((HOST, PORT))
            s.sendall('')
            reply = s.recv(1024)
            print("{}".format(reply))
        except socket.error as error:
            print("{}".format(error))

service_mappings = { 'ftp': ftp, 'http': http, 'https': https, 'ident': ident,
                      'netbios': netbios, 'smtp': smtp, 'snmpv1': snmpv1, 
                      'snmpv2': snmpv2, 'ssh': ssh, 'telnet': telnet, 
                      'tftp': tftp }

if __name__ == "__main__":
    try:
        while True:
            # If given more than two arguments after self, show usage
            if (len(sys.argv) > 3):
                usage()
                sys.exit(1)
            # If no arguments are specified, prompt
            elif (len(sys.argv)) is 1:
                HOST = input("Please enter a target host: ")
                PORT = input("Please enter a target service: ")
                select_service(PORT)(HOST)
                sys.exit(0)
            # If user requests help, show usage
            elif sys.argv[1] == "-h":
                usage()
                sys.exit(0)
            else:
                if sys.argv[2].isdigit():
                    if '0' < sys.argv[2] < '65536':
                        print("Here we go...")
                        HOST = sys.argv[1]
                        PORT = sys.argv[2]
                        PACKET = ''
                        banner_tcp(HOST, PORT, PACKET)
                    else:
                        print("Port out of range!")
                        break
                else:
                    select_service(sys.argv[2])(sys.argv[1])
                    break
    except KeyboardInterrupt:
        print("Exiting...\n")
    except TypeError:
        pass
